#include "Timerfd.hpp"

#include <bits/types/struct_itimerspec.h>
#include <cstdint>
#include <ctime>
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <string.h>

#include <iostream>

using std::cout;
using std::endl;


Timerfd::Timerfd(TimerCallback && cb, int init, int interval)
: _isLooping(false)
, _timerfd(createTimerfd())
, _epfd(createEpollFd())
, _init(init)
, _interval(interval)
, _cb(std::move(cb))
{
    cout << "_Timerfd:" << _timerfd << endl;
    cout << "_epfd:" << _epfd << endl;
}

Timerfd::~Timerfd()
{
    close(_timerfd);
    close(_epfd);
}

void Timerfd::start()
{
    _isLooping = true;
    addEpollReadFd();
    setTime(_init, _interval);//设置超时时间

    struct epoll_event ev;
    memset(&ev, 0, sizeof(ev));
    int nready = 0;
    while(_isLooping) {
        cout << "enter epoll loop" << endl;
        nready = epoll_wait(_epfd, &ev, 1, 6000);

        for(int i = 0; i < nready; ++i) {
            if(_timerfd == ev.data.fd) {
                //内核计时器超时，要进行处理
                handleRead();
                if(_cb) {
                    _cb();
                }
            }
        }
    }
}

void Timerfd::stop()
{
    cout << "timerfd::stop()" << endl;
    _isLooping = false;
    setTime(0, 0);//停止定时器
}

void Timerfd::setTime(int init, int interval)
{
    struct itimerspec value;
    value.it_value.tv_sec = init;
    value.it_value.tv_nsec = 0;
    value.it_interval.tv_sec = interval;
    value.it_interval.tv_nsec = 0;
    int ret = timerfd_settime(_timerfd, 0, &value, NULL);
    if(ret < 0) {
        perror("timerfd_settime");
    }
}

int Timerfd::createTimerfd()
{
    int fd = timerfd_create(CLOCK_REALTIME, 0);
    if(fd < 0) {
        perror("Timerfd");
    }
    return fd;
}

int Timerfd::createEpollFd()
{
    int fd = epoll_create1(0);
    if(fd < 0) {
        perror("epoll_create1");
    }
    return fd;
}

void Timerfd::addEpollReadFd()
{
    struct epoll_event ev;
    memset(&ev, 0, sizeof(ev));
    ev.data.fd = _timerfd;
    ev.events = EPOLLIN;
    int ret = epoll_ctl(_epfd, EPOLL_CTL_ADD, _timerfd, &ev);
    if(ret < 0) {
        perror("epoll_ctl");
    }
}

//对读事件进行处理
void Timerfd::handleRead()
{
    uint64_t howmany = 0;
    int ret = read(_timerfd, &howmany, sizeof(howmany));
    if(ret != sizeof(howmany)) {
        perror("read");
    }
}

